package com.ddtech.business.check.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ddtech.business.bank.entity.QuestionBankQuestion;
import com.ddtech.business.bank.entity.QuestionBankQuestionOption;
import com.ddtech.business.bank.service.QuestionBankQuestionOptionService;
import com.ddtech.business.bank.service.QuestionBankQuestionService;
import com.ddtech.business.check.entity.*;
import com.ddtech.business.check.mapper.CheckMapper;
import com.ddtech.business.check.query.CheckQuery;
import com.ddtech.business.check.service.*;
import com.ddtech.business.check.vo.req.AddCheck;
import com.ddtech.business.check.vo.req.CheckRecord;
import com.ddtech.business.check.vo.res.*;
import com.ddtech.business.common.BaseEntity;
import com.ddtech.business.common.BaseService;
import com.ddtech.business.constant.BusinessEnum;
import com.ddtech.business.constant.Del;
import com.ddtech.business.task.entity.Task;
import com.ddtech.business.task.service.TaskService;
import com.ddtech.business.train.entity.TrainPlan;
import com.ddtech.business.train.service.TrainPlanService;
import com.ddtech.business.web.entity.CollectRecord;
import com.ddtech.business.web.service.CollectRecordService;
import com.ddtech.exception.BizPreconditions;
import com.ddtech.framework.system.service.UserService;
import com.ddtech.framework.system.service.dto.UserDTO;
import com.ddtech.utils.PageUtil;
import com.ddtech.utils.SecurityUtils;
import com.ddtech.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 考核表 服务实现类
 * </p>
 *
 * @author bin_pu
 * @since 2023-02-06
 */
@Service
public class CheckServiceImpl extends BaseService<CheckMapper, Check> implements CheckService {
    @Autowired
    private CheckBankRelService checkBankRelService;
    @Autowired
    private CheckUserRecordService checkUserRecordService;
    @Autowired
    private TrainPlanService trainPlanService;
    @Autowired
    private TaskService taskService;
    @Resource
    private CheckMapper checkMapper;
    @Autowired
    private QuestionBankQuestionService questionBankQuestionService;
    @Autowired
    private QuestionBankQuestionOptionService questionBankQuestionOptionService;
    @Autowired
    private CheckUserQuestionService checkUserQuestionService;
    @Autowired
    private CheckUserQuestionOptionService checkUserQuestionOptionService;
    @Autowired
    private CheckUserAnswerService checkUserAnswerService;
    @Autowired
    private UserService userService;
    @Autowired
    private CollectRecordService collectRecordService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(AddCheck addCheck) {
        Check check = addCheck.getCheck();
        check.init();
        this.saveOrUpdate(check);
        checkBankRelService.saveCheckBank(check, addCheck.getBanks());
        checkUserRecordService.saveCheckUser(check, addCheck.getCheckUser());
    }

    @Override
    public Object pageList(CheckQuery checkQuery) {
        IPage<Map<String, Object>> page = checkMapper.getPageList(checkQuery.populatePage(), checkQuery.getCheckName(), checkQuery.getCheckType());
        return PageUtil.toPage(page.getRecords(), page.getTotal());
    }

    @Override
    public AddCheck getInfo(String checkId) {
        AddCheck addCheck = new AddCheck();
        Check check = this.getById(checkId);
        List<CheckBankRel> checkBank = checkBankRelService.getCheckBank(checkId);
        addCheck.setBanks(checkBank);
        addCheck.setCheck(check);
        addCheck.setCheckUser(checkUserRecordService.getCheckUser(checkId));
        return addCheck;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void del(String id) {
        Check check = this.getById(id);
        BizPreconditions.check(check == null, BusinessEnum.QUERY_ERROR.getMsg());
        LambdaQueryWrapper<Task> taskLambdaQueryWrapper = new LambdaQueryWrapper<>();
        taskLambdaQueryWrapper.eq(Task::getCheckId, id);
        taskLambdaQueryWrapper.eq(Task::getIsDelete, Del.FALSE.getStatus());
        List<Task> tasks = taskService.list(taskLambdaQueryWrapper);
        BizPreconditions.check(CollUtil.isNotEmpty(tasks), BusinessEnum.REL_TASK_NOT_DELETE.getMsg());
        LambdaQueryWrapper<TrainPlan> trainPlanLambdaQueryWrapper = new LambdaQueryWrapper<>();
        trainPlanLambdaQueryWrapper.eq(TrainPlan::getCheckId, id);
        trainPlanLambdaQueryWrapper.eq(TrainPlan::getIsDelete, Del.FALSE.getStatus());
        List<TrainPlan> trainPlanList = trainPlanService.list(trainPlanLambdaQueryWrapper);
        BizPreconditions.check(CollUtil.isNotEmpty(trainPlanList), BusinessEnum.REL_TRAIN_NOT_DELETE.getMsg());
        check.baseDelete();
        this.saveOrUpdate(check);
        checkUserRecordService.deleteCheckUser(id);
    }

    @Override
    public TodoCheckRes getCheckList(Integer type, String date) {
        TodoCheckRes todoCheckRes = new TodoCheckRes();
        Set<String> checkDate;
        List<Integer> checkType = new ArrayList<>();
        LambdaQueryWrapper<CheckUserRecord> checkUserRecordLambdaQueryWrapper = new LambdaQueryWrapper();
        LambdaQueryWrapper<Check> checkLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (type == 1) {
            checkType.addAll(Arrays.asList(1, 3, 4, 5));
            checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getIsFinish, 0);
            queryCriteria(checkLambdaQueryWrapper, date, checkType);
        } else if (type == 2) {
            checkType.addAll(Collections.singletonList(2));
            checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getIsFinish, 0);
            queryCriteria(checkLambdaQueryWrapper, date, checkType);
        } else if (type == 3) {
            checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getIsFinish, 1);
        }
        List<Check> todoCheckList = new ArrayList<>();
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getUserId, SecurityUtils.getUserId());
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getIsDelete, Del.FALSE.getStatus());
        List<CheckUserRecord> checkUserRecords = checkUserRecordService.list(checkUserRecordLambdaQueryWrapper);
        if (CollUtil.isNotEmpty(checkUserRecords)) {
            Set<String> todoCheckIds = checkUserRecords.stream().map(item -> item.getCheckId()).collect(Collectors.toSet());
            checkLambdaQueryWrapper.eq(Check::getIsDelete, Del.FALSE.getStatus());
            checkLambdaQueryWrapper.in(Check::getId, todoCheckIds);
            todoCheckList = this.list(checkLambdaQueryWrapper);
            if (CollUtil.isNotEmpty(todoCheckList)) {
                checkDate = todoCheckList.stream().map(item -> {
                    LocalDateTime startTime = item.getStartTime();
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    return formatter.format(startTime);
                }).collect(Collectors.toSet());
                if (StringUtils.isBlank(date)) {
                    todoCheckList = todoCheckList.stream().filter(check -> check.getIsStart() != 2).collect(Collectors.toList());
                }
                todoCheckRes.setCheckDate(checkDate);
            }
        }

        todoCheckRes.setToDoCheckList(todoCheckList);
        return todoCheckRes;
    }

    public void queryCriteria(LambdaQueryWrapper<Check> checkLambdaQueryWrapper, String date, List<Integer> checkType) {
        checkLambdaQueryWrapper.in(Check::getCheckType, checkType);
        if (StringUtils.isNotBlank(date)) {
            checkLambdaQueryWrapper.like(Check::getStartTime, date);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public QueTypeRes exam(String checkId) {
        LambdaQueryWrapper<CheckUserRecord> checkUserRecordLambdaQueryWrapper = new LambdaQueryWrapper();
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getCheckId, checkId);
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getUserId, SecurityUtils.getUserId());
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getIsDelete, Del.FALSE.getStatus());
        CheckUserRecord checkUserRecord = checkUserRecordService.getOne(checkUserRecordLambdaQueryWrapper);
        BizPreconditions.check(checkUserRecord == null, BusinessEnum.NO_JOIN_CHECK.getMsg());
        Check check = this.getById(checkId);
        if (checkUserRecord.getStartTime() == null) {
            LambdaQueryWrapper<CheckBankRel> relQuery = new LambdaQueryWrapper<>();
            relQuery.eq(CheckBankRel::getCheckId, checkId);
            List<CheckBankRel> checkBankRelList = checkBankRelService.list(relQuery);
            List<String> bankIds = checkBankRelList.stream().map(item -> item.getBankId()).collect(Collectors.toList());
            generateQueAndOpt(bankIds, check, SecurityUtils.getUserId());
            checkUserRecord.setStartTime(LocalDateTime.now());
            checkUserRecordService.saveOrUpdate(checkUserRecord);
        }
        QueTypeRes queTypeRes = getQueList(checkId);
        queTypeRes.setCheck(check);
        queTypeRes.setCheckUserRecord(checkUserRecord);
        //剩余时间计算
        Integer limeTime = check.getLimeTime();
        LocalDateTime startTime = checkUserRecord.getStartTime();
        LocalDateTime now = LocalDateTime.now();
        Duration between = Duration.between(startTime, now);
        long seconds = between.getSeconds();
        if (limeTime != null) {
            long limeTimeSeconds = limeTime * 60;
            long surplusTime = limeTimeSeconds - seconds;
            //网络延迟10s内
            surplusTime = surplusTime + 10 > limeTimeSeconds ? limeTimeSeconds : surplusTime;
            queTypeRes.setSurplusTime(surplusTime);
        }

        return queTypeRes;
    }

    public void generateQueAndOpt(List<String> bankIds, Check check, String userId) {
        QueryWrapper<QuestionBankQuestion> questionBankQuestionQueryWrapper = questionBankQuestionService.newValidQueryWrapper();
        questionBankQuestionQueryWrapper.in(QuestionBankQuestion.BANK_ID, bankIds);
        questionBankQuestionQueryWrapper.eq(BaseEntity.IS_DELETE, Del.FALSE.getStatus());
        Integer singleNum = 0;
        Integer multipleNum = 0;
        Integer judgeNum = 0;
        //随机
        if (check.getIsRandom() == 1) {
            questionBankQuestionQueryWrapper.orderByAsc("RAND()");
            //单选
            singleNum = check.getSingleNum();
            multipleNum = check.getMultipleNum();
            judgeNum = check.getJudgeNum();
        }
        List<QuestionBankQuestion> queList = questionBankQuestionService.list(questionBankQuestionQueryWrapper);
        //单选
        List<QuestionBankQuestion> singleQuestionList = queList.stream().filter(item -> item.getOptionType().equals(0)).collect(Collectors.toList());
        Integer havenSingleNum = singleNum >= singleQuestionList.size() ? singleQuestionList.size() : singleNum;
        addTypesOfProblems(check, userId, singleQuestionList, havenSingleNum);
        //多选
        List<QuestionBankQuestion> multipleQuestionList = queList.stream().filter(item -> item.getOptionType().equals(1)).collect(Collectors.toList());
        Integer havenMultipleNum = multipleNum >= multipleQuestionList.size() ? multipleQuestionList.size() : multipleNum;
        addTypesOfProblems(check, userId, multipleQuestionList, havenMultipleNum);
        //判断
        List<QuestionBankQuestion> judgeQuestionList = queList.stream().filter(item -> item.getOptionType().equals(2)).collect(Collectors.toList());
        Integer havenJudgeNum = judgeNum >= judgeQuestionList.size() ? judgeQuestionList.size() : judgeNum;
        addTypesOfProblems(check, userId, judgeQuestionList, havenJudgeNum);
    }

    private void addTypesOfProblems(Check check, String userId, List<QuestionBankQuestion> queList, int queNum) {
        int questionNum = 1;
        for (QuestionBankQuestion questionBankQuestion : queList) {
            if (queNum <= 0) {
                if (check.getIsRandom() == 1) {
                    break;
                }
            }
            String id = questionBankQuestion.getId();
            String newQueId = IdWorker.getIdStr();
            CheckUserQuestion question = new CheckUserQuestion(questionBankQuestion);
            question.setId(newQueId);
            question.setUserId(userId);
            question.setCheckId(check.getId());
            question.baseInsert();
            question.setQuestionNum(questionNum++);
            checkUserQuestionService.saveOrUpdate(question);
            //选项
            QueryWrapper<QuestionBankQuestionOption> questionBankQuestionOptionQueryWrapper = new QueryWrapper<>();
            questionBankQuestionOptionQueryWrapper.eq(QuestionBankQuestionOption.QUESTION_ID, id);
            List<QuestionBankQuestionOption> queOptList = questionBankQuestionOptionService.list(questionBankQuestionOptionQueryWrapper);
            for (QuestionBankQuestionOption questionBankQuestionOption : queOptList) {
                CheckUserQuestionOption questionOption = new CheckUserQuestionOption(questionBankQuestionOption);
                questionOption.init();
                questionOption.setUserId(userId);
                questionOption.setQuestionId(newQueId);
                questionOption.setCheckId(check.getId());
                checkUserQuestionOptionService.saveOrUpdate(questionOption);
            }
            queNum--;

        }
    }

    public QueTypeRes getQueList(String checkId) {
        QueTypeRes queTypeRes = new QueTypeRes();
        String userId = SecurityUtils.getUserId();
        LambdaQueryWrapper<CheckUserQuestion> checkUserQuestionLambdaQueryWrapper = new LambdaQueryWrapper();
        checkUserQuestionLambdaQueryWrapper.eq(CheckUserQuestion::getCheckId, checkId);
        checkUserQuestionLambdaQueryWrapper.eq(CheckUserQuestion::getUserId, userId);
        checkUserQuestionLambdaQueryWrapper.orderByAsc(CheckUserQuestion::getQuestionNum);
        List<CheckUserQuestion> queList = checkUserQuestionService.list(checkUserQuestionLambdaQueryWrapper);
        List<CheckUserQuestion> singleQuestionList = queList.stream().filter(item -> item.getOptionType().equals(0)).collect(Collectors.toList());
        queTypeRes.setSingleList(getTypeQuestion(userId, singleQuestionList));
        List<CheckUserQuestion> multipleQuestionList = queList.stream().filter(item -> item.getOptionType().equals(1)).collect(Collectors.toList());
        queTypeRes.setMultipleList(getTypeQuestion(userId, multipleQuestionList));
        List<CheckUserQuestion> judgeQuestionList = queList.stream().filter(item -> item.getOptionType().equals(2)).collect(Collectors.toList());
        queTypeRes.setJudgeList(getTypeQuestion(userId, judgeQuestionList));
        return queTypeRes;
    }

    public List<QueAndOpt> getTypeQuestion(String userId, List<CheckUserQuestion> questionList) {
        List<QueAndOpt> resultList = new ArrayList<>();
        for (CheckUserQuestion entity : questionList) {
            QueAndOpt bankQueAndOpt = new QueAndOpt(entity);
            LambdaQueryWrapper<CheckUserQuestionOption> checkUserQuestionOptionQueryWrapper = new LambdaQueryWrapper<>();
            checkUserQuestionOptionQueryWrapper.eq(CheckUserQuestionOption::getQuestionId, entity.getId());
            checkUserQuestionOptionQueryWrapper.eq(CheckUserQuestionOption::getUserId, userId);
            checkUserQuestionOptionQueryWrapper.eq(CheckUserQuestionOption::getIsDelete, Del.FALSE.getStatus());
            List<CheckUserQuestionOption> optList = checkUserQuestionOptionService.list(checkUserQuestionOptionQueryWrapper);
            bankQueAndOpt.setOptList(optList);
            LambdaQueryWrapper<CheckUserAnswer> checkUserAnswerLambdaQueryWrapper = new LambdaQueryWrapper<>();
            checkUserAnswerLambdaQueryWrapper.eq(CheckUserAnswer::getQuestionId, entity.getId());
            checkUserAnswerLambdaQueryWrapper.eq(CheckUserAnswer::getIsDelete, Del.FALSE.getStatus());
            CheckUserAnswer answer = checkUserAnswerService.getOne(checkUserAnswerLambdaQueryWrapper);
            if (answer != null) {
                bankQueAndOpt.setIsRight(answer.getIsRight());
                if (answer.getOptionId() != null) {
                    bankQueAndOpt.setChecked(answer.getOptionId());
                    bankQueAndOpt.setCheckedList(Arrays.asList(answer.getOptionId().split(",")));
                }
            }
            CollectRecord collectRecord = collectRecordService.getByBusId(entity.getId());
            if (collectRecord != null) {
                bankQueAndOpt.setCollect(true);
            }
            resultList.add(bankQueAndOpt);
        }
        return resultList;
    }

    @Override
    public Object getUserExamStatistics(Integer type) {
        Map<String, Object> resultMap = checkMapper.getUserExamStatistics(SecurityUtils.getUserId(), type);
        resultMap.put("latelyRecord", checkMapper.getLatelyExamInfo(SecurityUtils.getUserId(), type));
        return resultMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CheckUserRecord commit(CheckRecord checkRecord) {
        LambdaQueryWrapper<CheckUserRecord> checkUserRecordLambdaQueryWrapper = new LambdaQueryWrapper();
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getCheckId, checkRecord.getCheckId());
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getUserId, SecurityUtils.getUserId());
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getIsDelete, Del.FALSE.getStatus());

        CheckUserRecord checkUserRecord = checkUserRecordService.getOne(checkUserRecordLambdaQueryWrapper);
        BizPreconditions.check(checkUserRecord.getIsFinish() != null && checkUserRecord.getIsFinish() == 1, BusinessEnum.CHECK_COMMIT.getMsg());
        //设置用时
        String checkId = checkRecord.getCheckId();
        Check check = this.getById(checkId);
        LocalDateTime addTime = checkUserRecord.getStartTime();
        LocalDateTime now = LocalDateTime.now();
        //计算开始与结束的时间差
        Duration between = Duration.between(addTime, now);
        long seconds = between.getSeconds();
        Integer answerTimeLimit = check.getLimeTime() * 60;
        seconds = seconds > answerTimeLimit ? answerTimeLimit : seconds;
        checkUserRecord.setUseTime(seconds);
        checkUserRecord.setEndTime(LocalDateTime.now());
        List<CheckUserQuestion> questionList = checkRecord.getQueList();
        //判断是否选择正确答案
        int rightCount = 0;
        int wrongCount = 0;
        double checkScore = 0.0;
        //用户答案
        List<CheckUserAnswer> checkUserAnswerList = checkRecord.getCheckUserAnswerList();
        for (CheckUserQuestion checkUserQuestion : questionList) {
            for (CheckUserAnswer checkUserAnswer : checkUserAnswerList) {
                checkUserAnswer.init();
                if (checkUserQuestion.getId().equals(checkUserAnswer.getQuestionId())) {
                    checkUserAnswer.setBankQuestionId(checkUserQuestion.getBankQuestionId());
                    //获取正确答案
                    List<CheckUserQuestionOption> rightList = getRightOption(checkUserQuestion.getId());
                    // 单选
                    if (checkUserQuestion.getOptionType() == 0 || checkUserQuestion.getOptionType() == 2) {
                        String right = rightList.get(0).getId();
                        if (checkUserAnswer.getOptionId() != null && checkUserAnswer.getOptionId().equals(right)) {
                            rightCount++;
                            checkScore = checkScore + checkUserQuestion.getScore();
                            checkUserAnswer.setIsRight(1);
                            checkUserAnswerService.saveOrUpdate(checkUserAnswer);
                        } else {
                            wrongCount++;
                            checkUserAnswer.setIsRight(0);
                            checkUserAnswerService.saveOrUpdate(checkUserAnswer);
                        }
                    } else {
                        //多选
                        String optIds = checkUserAnswer.getOptionId();
                        List<String> ids = new ArrayList<>();
                        if (optIds != null && optIds.contains(",")) {
                            ids = Arrays.asList(optIds.split(","));
                        }
                        List<String> rightOpts = new ArrayList<>();
                        for (CheckUserQuestionOption examQuestionOption : rightList) {
                            rightOpts.add(examQuestionOption.getId());
                        }
                        //对比选项是否全对
                        if (ids.containsAll(rightOpts) && rightOpts.containsAll(ids)) {
                            rightCount++;
                            checkScore = checkScore + checkUserQuestion.getScore();
                            checkUserAnswer.setIsRight(1);
                            checkUserAnswerService.saveOrUpdate(checkUserAnswer);
                        } else {
                            wrongCount++;
                            checkUserAnswer.setIsRight(0);
                            checkUserAnswerService.saveOrUpdate(checkUserAnswer);
                        }
                    }
                }
            }
        }
        checkUserRecord.setRightCount(rightCount);
        checkUserRecord.setWrongCount(wrongCount);
        checkUserRecord.setSource(checkScore);
        checkUserRecord.setIsFinish(1);
        checkUserRecordService.saveOrUpdate(checkUserRecord);
        return checkUserRecord;
    }

    private List<CheckUserQuestionOption> getRightOption(String queId) {
        LambdaQueryWrapper<CheckUserQuestionOption> examQuestionOptionQueryWrapper = Wrappers.lambdaQuery();
        examQuestionOptionQueryWrapper.eq(CheckUserQuestionOption::getQuestionId, queId);
        examQuestionOptionQueryWrapper.eq(CheckUserQuestionOption::getIsTrue, 1);
        return checkUserQuestionOptionService.list(examQuestionOptionQueryWrapper);
    }


    @Override
    public ResUserCheckDetail getUserExamDetail(String recordId) {
        CheckUserRecord examStatistics = checkUserRecordService.getById(recordId);
        BizPreconditions.check(examStatistics == null, BusinessEnum.QUERY_ERROR.getMsg());
        Check exam = this.getById(examStatistics.getCheckId());
        LambdaQueryWrapper<CheckUserAnswer> examUserExerciseQueryWrapper = new LambdaQueryWrapper<>();
        examUserExerciseQueryWrapper.eq(CheckUserAnswer::getCheckId, exam.getId());
        examUserExerciseQueryWrapper.eq(CheckUserAnswer::getUserId, SecurityUtils.getUserId());
        List<CheckUserAnswer> examUserExerciseList = checkUserAnswerService.list(examUserExerciseQueryWrapper);
        QueTypeRes queTypeRes = getQueList(exam.getId());
        ResUserCheckDetail resUserCheckDetail = new ResUserCheckDetail(exam.getId(), exam.getCheckName(), examStatistics, examUserExerciseList, queTypeRes);
        return resUserCheckDetail;
    }

    @Override
    public ResRank getRank(String checkId, String userName, IPage pageableRequest) {
        Check check = this.getById(checkId);
        BizPreconditions.check(check == null, BusinessEnum.QUERY_ERROR.getMsg());
        LambdaQueryWrapper<CheckUserRecord> checkUserRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getCheckId, checkId);
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getIsFinish, 1);
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getIsDelete, Del.FALSE.getStatus());
        checkUserRecordLambdaQueryWrapper.orderByDesc(CheckUserRecord::getSource);
        checkUserRecordLambdaQueryWrapper.orderByAsc(CheckUserRecord::getUseTime);
        List<CheckUserRecord> list = checkUserRecordService.list(checkUserRecordLambdaQueryWrapper);
        IPage pagination = checkUserRecordService.page(pageableRequest, checkUserRecordLambdaQueryWrapper);
        Map<Double, Integer> rankMap = rankScore(list);
        list.stream().forEach(bean -> {
            bean.setRank(rankMap.get(bean.getSource()));
            UserDTO userDTO = userService.findById(bean.getUserId());
            bean.setUserHeadPortrait(userDTO.getAvatar());
            bean.setUserDept(userDTO.getDept().getName());
            bean.setIsPass(bean.getSource() == null || bean.getSource() < check.getStandardScore() ? "否" : "是");
        });
        LambdaQueryWrapper<CheckUserRecord> statisticsQueryWrapper = new LambdaQueryWrapper<>();
        statisticsQueryWrapper.eq(CheckUserRecord::getCheckId, checkId);
        statisticsQueryWrapper.eq(CheckUserRecord::getUserId, SecurityUtils.getUserId());
        statisticsQueryWrapper.eq(CheckUserRecord::getIsDelete, Del.FALSE.getStatus());
        CheckUserRecord checkUserRecord = checkUserRecordService.getOne(statisticsQueryWrapper);
        int manRank;
        if (checkUserRecord == null) {
            manRank = 0;
            checkUserRecord = new CheckUserRecord();
        } else {
            Integer rank = rankMap.get(checkUserRecord.getSource());
            manRank = rank;
        }
        if(StringUtils.isNotBlank(userName)){
            list=list.stream().filter(item->{
                if(StringUtils.isNotBlank(userName)){
                    return item.getUserName().contains(userName);
                }
                return true;
            }).collect(Collectors.toList());
            pagination.setTotal(list.size());
        }
        pagination.setRecords(list);
        return ResRank.builder()
                .manRank(manRank)
                .userId(SecurityUtils.getUserId())
                .userName(SecurityUtils.getName())
                .allCount(list.size())
                .examScore(checkUserRecord.getSource())
                .useTime(checkUserRecord.getUseTime())
                .pagination(pagination)
                .checkUserRecord(checkUserRecord)
                .build();
    }

    @Override
    public Object getUserExam(int page, int size, Integer type, String inputSearch) {
        List<UserExamRes> userExamResList = new ArrayList<>();
        LambdaQueryWrapper<CheckUserRecord> checkUserRecordLambdaQueryWrapper = new LambdaQueryWrapper();
        List<Integer> checkType = new ArrayList<>();
        if (type == 1) {
            checkType.addAll(Arrays.asList(1, 3, 4, 5));
        } else if (type == 2) {
            checkType.addAll(Collections.singletonList(2));
        }
        checkUserRecordLambdaQueryWrapper.in(CheckUserRecord::getCheckType, checkType);
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getIsFinish, 1);
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getUserId, SecurityUtils.getUserId());
        checkUserRecordLambdaQueryWrapper.eq(CheckUserRecord::getIsDelete, Del.FALSE.getStatus());
        checkUserRecordLambdaQueryWrapper.orderByDesc(CheckUserRecord::getEndTime);
        List<CheckUserRecord> checkUserRecords = checkUserRecordService.list(checkUserRecordLambdaQueryWrapper);
        if (CollUtil.isNotEmpty(checkUserRecords)) {
            for (CheckUserRecord checkUserRecord : checkUserRecords) {
                LambdaQueryWrapper<Check> checkLambdaQueryWrapper = new LambdaQueryWrapper<>();
                checkLambdaQueryWrapper.eq(Check::getId, checkUserRecord.getCheckId());
                if (StringUtils.isNotBlank(inputSearch)) {
                    checkLambdaQueryWrapper.like(Check::getCheckName, inputSearch);
                }
                Check check = this.getOne(checkLambdaQueryWrapper);
                if (check != null) {
                    UserExamRes userExamRes = new UserExamRes();
                    userExamRes.setId(check.getId());
                    userExamRes.setCheckName(check.getCheckName());
                    IPage rankPage = new Page(1, 10);
                    ResRank resRank = getRank(check.getId(), null, rankPage);
                    userExamRes.setResRank(resRank);
                    userExamResList.add(userExamRes);
                }
            }
        }
        return PageUtil.toPage(PageUtil.toPage(page, size, userExamResList), userExamResList.size());
    }


    public Map<Double, Integer> rankScore(List<CheckUserRecord> rankList) {
        Map<Double, Integer> map = new HashMap<>();
        List<Map.Entry<Double, List<CheckUserRecord>>> list = rankList.stream().collect(Collectors.groupingBy(CheckUserRecord::getSource)).entrySet()
                .stream().sorted((s1, s2) -> -Double.compare(s1.getKey(), s2.getKey())).collect(Collectors.toList());
        int index = 1;
        for (Map.Entry<Double, List<CheckUserRecord>> entry : list) {
            map.put(entry.getKey(), index);
            index += entry.getValue().size();
        }
        return map;
    }
}
